grammar TableAnalyzerExpressions;

tokens
{
	
	OR='or';
	AND='and';
	NOT='not';
	XOR='xor';
}
@header
{
package net.disy.expression.parser.antlr;
import net.disy.expression.objectmodel.*;
import net.disy.expression.objectmodel.functions.*;
import net.disy.expression.objectmodel.operators.*;
import net.disy.expression.objectmodel.constants.*;
}
@lexer::header {
package net.disy.expression.parser.antlr;
import net.disy.expression.objectmodel.*;
import net.disy.expression.objectmodel.functions.*;
import net.disy.expression.objectmodel.operators.*;
import net.disy.expression.objectmodel.constants.*;
}

fragment DIGIT
	: ('0'..'9')	
	;

/*
fragment CHAR
	: ('\u0009' | '\u000A' | '\u000D' | '\u0020'..'\uD7FF' | '\uE000'..'\uFFFD' )
	;
*/

VARIABLENAME
	: 'A'..'Z' ('A'..'Z')?
	;
	
INTEGER
  : DIGIT+
  ;
  
DOUBLE
  : DIGIT+ DOT DIGIT+
  ;

fragment CHAR
	: ('A'..'Z'|'a'..'z'|DIGIT|DOT)
	;

fragment ESCAPEAPOS 	   
	: QUOTE QUOTE
	;
	
fragment CHARNOAPOS	   
	: ~( ~CHAR | QUOTE )
	;	
	
fragment QUOTE		   
	: '"'
	;
	

COMMA
	: ','
	;

DOT
	: '.'
	;
/*	
fragment LETTER
	: ('A'..'Z'|'a'..'z')
	;
	
UNQUOTEDLITERAL
	: LETTER+
	;
*/

fragment CHARNOSPECIAL	   
	: ~( ~CHAR | QUOTE | COMMA | OPENINGBRACKET | CLOSINGBRACKET )
	;	
	
QUOTEDLITERAL		   
	: (QUOTE (ESCAPEAPOS | CHARNOAPOS) + QUOTE)
	;
UNQUOTEDLITERAL
	:	CHARNOSPECIAL+;

OPENINGBRACKET
	: '('
	;
	
CLOSINGBRACKET
	: ')'
	;	

WHITESPACE
  : ('\u0020'){$channel=HIDDEN;}
  ;	

calculationRule returns [IExpression expvalue]
	: '=' op1=expression {$expvalue = op1; }
	;
	
expression returns [IExpression expvalue]
	: op1=orExpression {$expvalue = op1; }
	;
	
orExpression returns [IExpression expvalue]
	: op1=andExpression {$expvalue = op1; }
	( 'or' op2=andExpression {$expvalue = new OrOperator($expvalue, op2); }
	| 'xor' op2=andExpression {$expvalue = new XorOperator($expvalue, op2); }
	)*
	;
	
andExpression returns [IExpression expvalue]
	: op1=negatedExpression {$expvalue = op1; }
	( 'and' op2=negatedExpression {$expvalue = new AndOperator($expvalue, op2); })*
	;

negatedExpression returns [IExpression expvalue]
	: NOT op=relationalExpression {$expvalue=new NegationOperator(op);}
	| op=relationalExpression {$expvalue=op;}
	;	

relationalExpression returns [IExpression expvalue]
	: op1=additionExpression {$expvalue = op1; }
	( '<' op2=additionExpression {$expvalue = new LtOperator($expvalue, op2); }
	| '>' op2=additionExpression {$expvalue = new GtOperator($expvalue, op2); }
	| '<=' op2=additionExpression {$expvalue = new LeOperator($expvalue, op2); }
	| '>=' op2=additionExpression {$expvalue = new GeOperator($expvalue, op2); }
	| '=' op2=additionExpression {$expvalue = new EqOperator($expvalue, op2); }
	| '<>' op2=additionExpression {$expvalue = new NeOperator($expvalue, op2); }
	)*	
	;		
	
additionExpression returns [IExpression expvalue]
	: op1=multiplicationExpression {$expvalue = op1; }
	( '+' op2=multiplicationExpression {$expvalue = new PlusOperator($expvalue, op2); }
	| '-' op2=multiplicationExpression {$expvalue = new MinusOperator($expvalue, op2); }
	)*
	;
	
multiplicationExpression returns [IExpression expvalue]
	: op1=powerExpression {$expvalue = op1; } 
	(	'*' op2=powerExpression {$expvalue = new MultiplyOperator($expvalue, op2); } 
	| '/' op2=powerExpression {$expvalue = new DivideOperator($expvalue, op2); }
	| 'mod' op2=powerExpression {$expvalue = new ModuloOperator($expvalue, op2); }  
	)*
	;	
	
powerExpression returns [IExpression expvalue]
  : op1=unaryExpression {$expvalue = op1; } 
  ('^' op2=unaryExpression {$expvalue = new PowerOperator(op1, op2); })?
  ;
	
unaryExpression returns [IExpression expvalue]
	: '-' op=primaryExpression {$expvalue= new NegativeOperator(op);}
	| op=primaryExpression{ $expvalue=op;} 
	;	
	
primaryExpression returns [IExpression expvalue]
	: op=valueExpression { $expvalue=op;} 
	| op=functionExpression { $expvalue=op;} 
	| op=bracketExpression { $expvalue=op;} 
	| op=ifThenElseExpression { $expvalue=op;} 
	;
	
ifThenElseExpression returns [IExpression expvalue]
	: 'if' ev1=expression 'then' ev2=expression 'else' ev3=expression
	{
	 $expvalue=new IfThenElseExpression(ev1, ev2, ev3);
	}
	;
	
valueExpression returns [IExpression expvalue]
	: ev1=constantExpression {$expvalue=ev1;} 
	| ev2=literalExpression {$expvalue=ev2;} 
	| ev3=numberExpression {$expvalue=ev3;} 
	| ev4=variableExpression {$expvalue=ev4;} 
	;
	
constantExpression returns [IExpression expvalue]
	: 'PI' {$expvalue = new PiExpression();} 
	| 'null' {$expvalue = new NullExpression();} 
	| 'true' {$expvalue = new TrueExpression();} 
	| 'false' {$expvalue = new FalseExpression();} 
	;
	
functionExpression returns [IExpression expvalue]
	: 
	( op=isBetweenFunction
	| op=toIntegerFunction
	| op=toDoubleFunction
	| op=replaceNullFunction
	| op=lnFunction
	| op=logFunction
	| op=expFunction
	| op=sqrFunction
	| op=sqrtFunction
	| op=cosFunction
	| op=sinFunction
	| op=tanFunction
	| op=acosFunction
	| op=asinFunction
	| op=atanFunction
	| op=coshFunction
	| op=sinhFunction
	| op=tanhFunction
	| op=intFunction
	| op=absFunction
	| op=oppFunction
	| op=concatFunction
	)
	{ $expvalue=op;} 
	;
	
isBetweenFunction returns [IExpression expvalue]
	: 'isBetween' OPENINGBRACKET arg1=functionArgument COMMA arg2=functionArgument COMMA arg3=functionArgument CLOSINGBRACKET
	{
	$expvalue=new IsBetweenFunction(arg1, arg2, arg3);
	}
	;
	
concatFunction returns [IExpression expvalue]
	: 'concat' OPENINGBRACKET arg1=functionArgument COMMA arg2=functionArgument 
	{
	ConcatFunction cf = new ConcatFunction();
	$expvalue=cf;
	cf.addArgument(arg1);
	cf.addArgument(arg2);
	}
	(COMMA arg3=functionArgument {cf.addArgument(arg3);})* CLOSINGBRACKET
	;
	
toIntegerFunction returns [IExpression expvalue]
	: 'toInteger' OPENINGBRACKET op=functionArgument {$expvalue=new ToIntegerFunction(op);} CLOSINGBRACKET
	;
	
toDoubleFunction returns [IExpression expvalue]
	: 'toDouble' OPENINGBRACKET op=functionArgument {$expvalue=new ToDoubleFunction(op);} CLOSINGBRACKET
	;
	
replaceNullFunction returns [IExpression expvalue]
	: 'replaceNull' OPENINGBRACKET arg1=functionArgument COMMA arg2=functionArgument CLOSINGBRACKET
  {
   $expvalue=new ReplaceNullFunction(arg1, arg2);
  }
	;

lnFunction returns [IExpression expvalue]
	: 'ln'  OPENINGBRACKET op=functionArgument {$expvalue=new LnFunction(op);} CLOSINGBRACKET
	;
	
logFunction returns [IExpression expvalue]
	: 'log'  OPENINGBRACKET op=functionArgument {$expvalue=new LogFunction(op);} CLOSINGBRACKET
	;
	
expFunction returns [IExpression expvalue]
	: 'exp'  OPENINGBRACKET op=functionArgument {$expvalue=new ExpFunction(op);} CLOSINGBRACKET
	;
	
sqrFunction returns [IExpression expvalue]
	: 'sqr'  OPENINGBRACKET op=functionArgument {$expvalue=new SqrFunction(op);} CLOSINGBRACKET
	;
	
sqrtFunction returns [IExpression expvalue]
	: 'sqrt'  OPENINGBRACKET op=functionArgument {$expvalue=new SqrtFunction(op);} CLOSINGBRACKET
	;
	
cosFunction returns [IExpression expvalue]
	: 'cos'  OPENINGBRACKET op=functionArgument {$expvalue=new CosFunction(op);} CLOSINGBRACKET
	;

sinFunction returns [IExpression expvalue]
	: 'sin'  OPENINGBRACKET op=functionArgument {$expvalue=new SinFunction(op);} CLOSINGBRACKET
	;
	
tanFunction returns [IExpression expvalue]
	: 'tan'  OPENINGBRACKET op=functionArgument {$expvalue=new TanFunction(op);} CLOSINGBRACKET
	;

acosFunction returns [IExpression expvalue]
	: 'acos'  OPENINGBRACKET op=functionArgument {$expvalue=new AcosFunction(op);} CLOSINGBRACKET
	;

asinFunction returns [IExpression expvalue]
	: 'asin'  OPENINGBRACKET op=functionArgument {$expvalue=new AsinFunction(op);} CLOSINGBRACKET
	;
	
atanFunction returns [IExpression expvalue]
	: 'atan'  OPENINGBRACKET op=functionArgument {$expvalue=new AtanFunction(op);} CLOSINGBRACKET
	;
	
coshFunction returns [IExpression expvalue]
	: 'cosh'  OPENINGBRACKET op=functionArgument {$expvalue=new CoshFunction(op);} CLOSINGBRACKET
	;

sinhFunction returns [IExpression expvalue]
	: 'sinh'  OPENINGBRACKET op=functionArgument {$expvalue=new SinhFunction(op);} CLOSINGBRACKET
	;
	
tanhFunction returns [IExpression expvalue]
	: 'tanh'  OPENINGBRACKET op=functionArgument {$expvalue=new TanhFunction(op);} CLOSINGBRACKET
	;
	
intFunction returns [IExpression expvalue]
	: 'int'  OPENINGBRACKET op=functionArgument {$expvalue=new IntFunction(op);} CLOSINGBRACKET
	;
	
absFunction returns [IExpression expvalue]
	: 'abs'  OPENINGBRACKET op=functionArgument {$expvalue=new AbsFunction(op);} CLOSINGBRACKET
	;
	
oppFunction returns [IExpression expvalue]
	: 'opp'  OPENINGBRACKET op=functionArgument {$expvalue=new OppFunction(op);} CLOSINGBRACKET
	;

literalExpression returns[IExpression expvalue]
	: op=unquotedLiteralExpression 
	{
	 $expvalue=op;
	}
	| op=quotedLiteralExpression
	{
   $expvalue=op;
  }
	;	
	
	
variableExpression returns[IExpression expvalue]
	: ev=VARIABLENAME 
	{
   $expvalue = new VariableExpression(ev.getText());
  }
	;	
	
numberExpression returns [IExpression expvalue]
	: ev=INTEGER {$expvalue = new NumberExpression(Integer.parseInt(ev.getText()));}
	| ev=DOUBLE {$expvalue = new NumberExpression(Double.parseDouble(ev.getText()));}
	;
	
unquotedLiteralExpression returns [IExpression expvalue]
	: UNQUOTEDLITERAL
	{
   $expvalue = new StringExpression($UNQUOTEDLITERAL.getText());
  }
	;
	
quotedLiteralExpression returns [IExpression expvalue]
	: QUOTEDLITERAL
	{
   $expvalue = new StringExpression($QUOTEDLITERAL.getText().substring(1, $QUOTEDLITERAL.getText().length() - 1));
  }
	; 
	
bracketExpression returns [IExpression expvalue]
	: OPENINGBRACKET op=expression {$expvalue=op;} CLOSINGBRACKET
	;

functionArgument returns [IExpression expvalue]
	: op=expression
	{
	 $expvalue=op;
	}
	;

//without it the parser can't parse well
dummyRule
	: expression
	;